﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using HML.Design;

namespace HML
{
    /// <summary>
    ///  图案手势控件
    /// </summary>
    [Description("图案手势控件")]
    [DefaultProperty("TrajectoryVisible")]
    [DefaultEvent("Complete")]
    [TypeConverter(typeof(PropertyOrderConverter))]
    [Designer(typeof(PatternLockDesigner))]
    [ToolboxItem(true)]
    [ToolboxBitmap(typeof(PatternLock), "Controls.PatternLock.Resources.PatternLock.bmp")]
    public class PatternLock : DpiControl, ISkinObject
    {
        #region 主题

        private SkinObjectXmlMetadata skinObjectXmlMetadata = null;
        /// <summary>
        /// 主题对象在主题文件信息
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual SkinObjectXmlMetadata SkinObjectXmlMetadata
        {
            get
            {
                if (this.skinObjectXmlMetadata == null)
                    this.skinObjectXmlMetadata = new SkinObjectXmlMetadata(Assembly.GetAssembly(typeof(PatternLock)).GetName().Name, typeof(PatternLock).Name);

                return this.skinObjectXmlMetadata;
            }
        }

        private SkinController skinController = null;
        /// <summary>
        /// 主题控制器
        /// </summary>
        [Description("主题控制器")]
        [Category("杂项")]
        [PropertyOrder(-360)]
        [DefaultValue(null)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinController SkinController
        {
            get { return this.skinController; }
            set
            {
                if (this.skinController == value)
                    return;

                if (this.skinController != null)
                    this.skinController.RemoveSkinObject(this);

                this.skinController = value;

                if (this.skinController != null)
                    this.skinController.AddSkinObject(this);
            }
        }

        private SkinEnabledState skinEnabled= SkinEnabledState.Auto;
        /// <summary>
        /// 主题是否启用
        /// </summary>
        [Description("主题是否启用")]
        [Category("杂项")]
        [PropertyOrder(-300)]
        [DefaultValue(SkinEnabledState.Auto)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinEnabledState SkinEnabled
        {
            get { return this.skinEnabled; }
            set
            {
                if (this.skinEnabled == value)
                    return;

                this.skinEnabled = value;
                this.OnSkinChanged();
            }
        }

        private SkinStyle skinStyle = SkinStyle.Normal;
        /// <summary>
        /// 主题风格
        /// </summary>
        [Description("主题风格")]
        [Category("杂项")]
        [PropertyOrder(-260)]
        [DefaultValue(SkinStyle.Normal)]
        [RefreshProperties(RefreshProperties.All)]
        public virtual SkinStyle SkinStyle
        {
            get { return this.skinStyle; }
            set
            {
                if (this.skinStyle == value)
                    return;

                this.skinStyle = value;
                this.OnSkinChanged();
            }
        }

        private StyleAppearanceObject stateAppearance;
        /// <summary>
        /// 风格外观
        /// </summary>
        [Description("风格外观")]
        [Category("杂项")]
        [PropertyOrder(-200)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public StyleAppearanceObject StyleAppearance
        {
            get
            {
                if (this.stateAppearance == null)
                    this.stateAppearance = new StyleAppearanceObject(this, null);
                return this.stateAppearance;
            }
        }

        /// <summary>
        /// 主题已更改
        /// </summary>
        public virtual void OnSkinChanged()
        {
            SkinManager.SyncSkinValueToProperty(this);
            this.Invalidate();
        }

        private ISkinObject followSkinObject = null;
        /// <summary>
        /// 主题设置跟随指定主题对象（自己的设置不再生效，提供给代码使用）
        /// </summary>
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [Localizable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual ISkinObject FollowSkinObject
        {
            get { return this.followSkinObject; }
            set
            {
                if (this.followSkinObject == value)
                    return;

                this.followSkinObject = value;
                this.OnSkinChanged();
            }
        }

        public virtual bool GetSkinObjectSkinStateCore()
        {
            return SkinManager.GetSkinObjectSkinState(this.FollowSkinObject ?? this);
        }

        void ISkinObject.InitializeInvalidate()
        {
            this.InitializeElement();
            this.Invalidate();
        }

        void ISkinObject.Invalidate()
        {
            this.Invalidate();
        }

        #endregion

        #region 新增事件

        public delegate void CompleteEventHandler(object sender, PatternLockCompleteEventArgs e);
        private static readonly object EventComplete = new object();
        /// <summary>
        /// 手势完成事件
        /// </summary>
        [Description("手势完成事件")]
        public event CompleteEventHandler Complete
        {
            add { Events.AddHandler(EventComplete, value); }
            remove { Events.RemoveHandler(EventComplete, value); }
        }

        #endregion

        #region 停用事件

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler PaddingChanged
        {
            add { base.PaddingChanged += value; }
            remove { base.PaddingChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabIndexChanged
        {
            add { base.TabIndexChanged += value; }
            remove { base.TabIndexChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TabStopChanged
        {
            add { base.TabStopChanged += value; }
            remove { base.TabStopChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyDown
        {
            add { base.KeyDown += value; }
            remove { base.KeyDown -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyUp
        {
            add { base.KeyUp += value; }
            remove { base.KeyUp -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyPressEventHandler KeyPress
        {
            add { base.KeyPress += value; }
            remove { base.KeyPress -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event PreviewKeyDownEventHandler PreviewKeyDown
        {
            add { base.PreviewKeyDown += value; }
            remove { base.PreviewKeyDown -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TextChanged
        {
            add { base.TextChanged += value; }
            remove { base.TextChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler FontChanged
        {
            add { base.FontChanged += value; }
            remove { base.FontChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler RightToLeftChanged
        {
            add { base.RightToLeftChanged += value; }
            remove { base.RightToLeftChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ImeModeChanged
        {
            add { base.ImeModeChanged += value; }
            remove { base.ImeModeChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageChanged
        {
            add { base.BackgroundImageChanged += value; }
            remove { base.BackgroundImageChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackgroundImageLayoutChanged
        {
            add { base.BackgroundImageLayoutChanged += value; }
            remove { base.BackgroundImageLayoutChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BackColorChanged
        {
            add { base.BackColorChanged += value; }
            remove { base.BackColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ForeColorChanged
        {
            add { base.ForeColorChanged += value; }
            remove { base.ForeColorChanged -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Click
        {
            add { base.Click += value; }
            remove { base.Click -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseClick
        {
            add { base.MouseClick += value; }
            remove { base.MouseClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DoubleClick
        {
            add { base.DoubleClick += value; }
            remove { base.DoubleClick -= value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseDoubleClick
        {
            add { base.MouseDoubleClick += value; }
            remove { base.MouseDoubleClick -= value; }
        }

        #endregion

        #region 新增属性

        private bool trajectoryVisible = true;
        /// <summary>
        /// 是否显示手势轨迹
        /// </summary>
        [Description("是否显示手势轨迹")]
        [Category("杂项")]
        [PropertyOrder(-198)]
        [DefaultValue(true)]
        public bool TrajectoryVisible
        {
            get { return this.trajectoryVisible; }
            set
            {
                if (this.trajectoryVisible == value)
                    return;

                this.trajectoryVisible = value;
                this.Invalidate();
            }
        }

        #endregion

        #region 重写属性

        protected override Size DefaultSize
        {
            get { return new Size(250, 250); }
        }

        protected override ImeMode DefaultImeMode
        {
            get { return ImeMode.Disable; }
        }

        #endregion

        #region 停用属性

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new Padding Padding
        {
            get { return base.Padding; }
            set { base.Padding = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new int TabIndex
        {
            get { return base.TabIndex; }
            set { base.TabIndex = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new bool TabStop
        {
            get { return base.TabStop; }
            set { base.TabStop = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string Text
        {
            get { return base.Text; }
            set { base.Text = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override Font Font
        {
            get { return base.Font; }
            set { base.Font = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public override RightToLeft RightToLeft
        {
            get { return base.RightToLeft; }
            set { base.RightToLeft = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        public new ImeMode ImeMode
        {
            get { return base.ImeMode; }
            set { base.ImeMode = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Image BackgroundImage
        {
            get { return base.BackgroundImage; }
            set { base.BackgroundImage = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override ImageLayout BackgroundImageLayout
        {
            get { return base.BackgroundImageLayout; }
            set { base.BackgroundImageLayout = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color BackColor
        {
            get { return this.StyleAppearance.BackColor; }
            set { }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Color ForeColor
        {
            get { return this.StyleAppearance.TextColor; }

            set { }
        }

        #endregion

        #region 字段

        /// <summary>
        /// 当前鼠标已按下的对象
        /// </summary>
        private bool mousedownobject = false;
        /// <summary>
        /// 当前鼠标已按下的坐标
        /// </summary>
        private Point mousedownpoint = Point.Empty;
        /// <summary>
        /// 操作状态
        /// </summary>
        private PatternLockOperateStatus operateStatus = PatternLockOperateStatus.Normal;
        /// <summary>
        /// 已选中选项
        /// </summary>
        private Dictionary<int, string> selectedPatternLockItems = new Dictionary<int, string>();
        /// <summary>
        /// 选项集合
        /// </summary>
        private List<PatternLockItem> patternLockItems = new List<PatternLockItem>()
        {
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="1"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="2"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="3"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="4"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="5"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="6"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="7"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="8"},
        new PatternLockItem(){ OutRect= RectangleF.Empty, GP=new GraphicsPath(), Value="9"},
        };

        #endregion

        public PatternLock()
        {
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(ControlStyles.StandardClick, false);//自定义单击事件逻辑
            SetStyle(ControlStyles.StandardDoubleClick, false);//停用双加事件

            this.TabStop = false;
            this.InitializeElement();
            this.OnSkinChanged();

        }

        #region 重写

        protected override void OnScaleDpiChangedInitialize()
        {
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if (this.patternLockItems == null)
                return;

            Graphics g = e.Graphics;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            float lineThickness = this.patternLockItems[0].InRect.Width;

            SolidBrush in_round_normal_sb = new SolidBrush(this.StyleAppearance.Normal.ThumbColor);
            SolidBrush out_round_normal_sb = new SolidBrush(Color.FromArgb(50, this.StyleAppearance.Normal.ThumbColor));
            Pen out_round_normal_pen = new Pen(this.StyleAppearance.Normal.ThumbColor, lineThickness / 3f) { Alignment = PenAlignment.Outset };
            Pen in_line_normal_pen = new Pen(Color.FromArgb(150, this.StyleAppearance.Normal.ThumbColor), lineThickness) { Alignment = PenAlignment.Center, StartCap = LineCap.Round, EndCap = LineCap.Round };

            if (!this.TrajectoryVisible)
            {
                for (int i = 0; i < this.patternLockItems.Count; i++)
                {
                    g.FillEllipse(in_round_normal_sb, this.patternLockItems[i].InRect);
                }
            }
            else
            {
                if (this.operateStatus == PatternLockOperateStatus.Normal)
                {
                    for (int i = 0; i < this.patternLockItems.Count; i++)
                    {
                        g.FillEllipse(in_round_normal_sb, this.patternLockItems[i].InRect);
                    }
                }
                else if (this.operateStatus == PatternLockOperateStatus.Sliding)
                {
                    out_round_normal_sb.Color = Color.FromArgb(50, this.StyleAppearance.Executing.ThumbColor);
                    out_round_normal_pen.Color = this.StyleAppearance.Executing.ThumbColor;
                    in_line_normal_pen.Color = Color.FromArgb(150, this.StyleAppearance.Executing.ThumbColor);
                    for (int i = 0; i < this.patternLockItems.Count; i++)
                    {
                        if (this.selectedPatternLockItems.Keys.Contains(i))
                        {
                            in_round_normal_sb.Color = this.StyleAppearance.Executing.ThumbColor;
                            g.FillEllipse(out_round_normal_sb, this.patternLockItems[i].OutRect);
                            g.DrawEllipse(out_round_normal_pen, this.patternLockItems[i].OutRect);
                        }
                        else
                        {
                            in_round_normal_sb.Color = this.StyleAppearance.Normal.ThumbColor;
                        }
                        g.FillEllipse(in_round_normal_sb, this.patternLockItems[i].InRect);
                    }

                    for (int j = 0; j < this.selectedPatternLockItems.Count - 1; j++)
                    {
                        g.DrawLine(in_line_normal_pen, this.patternLockItems[this.selectedPatternLockItems.ElementAt(j).Key].CenterPoint, this.patternLockItems[this.selectedPatternLockItems.ElementAt(j + 1).Key].CenterPoint);
                    }
                    if (this.selectedPatternLockItems.Count > 0)
                    {
                        g.DrawLine(in_line_normal_pen, this.patternLockItems[this.selectedPatternLockItems.ElementAt(this.selectedPatternLockItems.Count - 1).Key].CenterPoint, this.mousedownpoint);
                    }
                }
                else if (this.operateStatus == PatternLockOperateStatus.Complete)
                {
                    for (int i = 0; i < this.patternLockItems.Count; i++)
                    {
                        if (this.selectedPatternLockItems.Keys.Contains(i))
                        {
                            g.FillEllipse(out_round_normal_sb, this.patternLockItems[i].OutRect);
                            g.DrawEllipse(out_round_normal_pen, this.patternLockItems[i].OutRect);
                        }
                        g.FillEllipse(in_round_normal_sb, this.patternLockItems[i].InRect);
                    }

                    for (int j = 0; j < this.selectedPatternLockItems.Count - 1; j++)
                    {
                        g.DrawLine(in_line_normal_pen, this.patternLockItems[this.selectedPatternLockItems.ElementAt(j).Key].CenterPoint, this.patternLockItems[this.selectedPatternLockItems.ElementAt(j + 1).Key].CenterPoint);
                    }
                }
                else if (this.operateStatus == PatternLockOperateStatus.Error)
                {
                    in_round_normal_sb.Color = this.StyleAppearance.Error.ThumbColor;
                    out_round_normal_sb.Color = Color.FromArgb(50, this.StyleAppearance.Error.ThumbColor);
                    out_round_normal_pen.Color = this.StyleAppearance.Error.ThumbColor;
                    in_line_normal_pen.Color = Color.FromArgb(150, this.StyleAppearance.Error.ThumbColor);
                    for (int i = 0; i < this.patternLockItems.Count; i++)
                    {
                        if (this.selectedPatternLockItems.Keys.Contains(i))
                        {
                            g.FillEllipse(out_round_normal_sb, this.patternLockItems[i].OutRect);
                            g.DrawEllipse(out_round_normal_pen, this.patternLockItems[i].OutRect);
                        }
                        g.FillEllipse(in_round_normal_sb, this.patternLockItems[i].InRect);
                    }

                    for (int j = 0; j < this.selectedPatternLockItems.Count - 1; j++)
                    {
                        g.DrawLine(in_line_normal_pen, this.patternLockItems[this.selectedPatternLockItems.ElementAt(j).Key].CenterPoint, this.patternLockItems[this.selectedPatternLockItems.ElementAt(j + 1).Key].CenterPoint);
                    }
                }
            }


            if (in_round_normal_sb != null)
                in_round_normal_sb.Dispose();
            if (out_round_normal_sb != null)
                out_round_normal_sb.Dispose();
            if (out_round_normal_pen != null)
                out_round_normal_pen.Dispose();
            if (in_line_normal_pen != null)
                in_line_normal_pen.Dispose();

        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);

            if (this.operateStatus == PatternLockOperateStatus.Sliding)
            {
                this.Reset();
            }
        }

        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);

            if (!this.Enabled)
            {
                this.Reset();
            }
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

            if (!this.Visible)
            {
                this.Reset();
            }
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);

            if (this.Parent == null)
            {
                this.Reset();
            }
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);

            this.mousedownobject = false;
            this.mousedownpoint = Point.Empty;
            this.CompleteTrigger();
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!this.Focused)
            {
                this.Focus();
            }

            if (e.Button == MouseButtons.Left)
            {
                if (this.operateStatus == PatternLockOperateStatus.Normal)
                {
                    for (int i = 0; i < this.patternLockItems.Count; i++)
                    {
                        if (this.patternLockItems[i].GP.IsVisible(e.Location))
                        {
                            if (this.selectedPatternLockItems.Count == 0)
                            {
                                this.mousedownobject = true;
                                this.operateStatus = PatternLockOperateStatus.Sliding;
                            }

                            if (!this.selectedPatternLockItems.Keys.Contains(i))
                            {
                                this.selectedPatternLockItems.Add(i, this.patternLockItems[i].Value);
                                this.mousedownpoint = e.Location;
                                this.Invalidate();
                                break;
                            }
                        }
                    }
                }
            }

            base.OnMouseDown(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            this.mousedownobject = false;
            this.mousedownpoint = Point.Empty;
            this.CompleteTrigger();

            base.OnMouseUp(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (this.mousedownobject && this.operateStatus == PatternLockOperateStatus.Sliding)
                {
                    for (int i = 0; i < this.patternLockItems.Count; i++)
                    {
                        if (this.patternLockItems[i].GP.IsVisible(e.Location))
                        {
                            if (!this.selectedPatternLockItems.Keys.Contains(i))
                            {
                                this.selectedPatternLockItems.Add(i, this.patternLockItems[i].Value);
                            }
                            break;
                        }
                    }
                    this.mousedownpoint = e.Location;
                    this.Invalidate();
                }
            }

            base.OnMouseMove(e);
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            this.InitializeElement();
            this.Invalidate();
        }

        protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
        {
            if (this.Width == width && this.Height != height)
            {
                width = height;
            }
            else
            {
                height = width;
            }

            base.SetBoundsCore(x, y, width, height, specified);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.patternLockItems != null)
                {
                    List<PatternLockItem> patternLockItems_tmp = this.patternLockItems;
                    this.patternLockItems = null;
                    for (int i = 0; i < patternLockItems_tmp.Count; i++)
                    {
                        patternLockItems_tmp[i].GP.Dispose();
                    }
                }
            }
            base.Dispose(disposing);
        }

        #endregion

        #region 虚方法

        protected virtual void OnComplete(PatternLockCompleteEventArgs e)
        {
            CompleteEventHandler handler = Events[EventComplete] as CompleteEventHandler;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        #endregion

        #region 公开方法

        /// <summary>
        /// 初始化控件内部元素布局
        /// </summary>
        public void InitializeElement()
        {
            /*解锁圆形的直径自动计算方式（解锁圆形包括内圆、外圆、外圆边厚度）
            1.解锁圆形的内圆直径=解锁圆形的外圆直径五分之一
            2.解锁圆形之间间距=解锁圆形的外圆直径十分之七
            3.解锁圆形的外圆边厚度=解锁圆形的内圆直径三分之一
             
             控件工作区的矩形宽度=内边距*2+外圆直径*3+圆形之间间距*2+外圆边厚度*2
            */

            float rect_width = (float)this.ClientRectangle.Width;
            float draw_padding = 2f;//绘图区内边距
            float draw_width = rect_width - draw_padding * 2f;//绘图区宽度
            float circle_out_diameter = draw_width * 15f / 68f;//外圆直径  公式原型：rect_width=(draw_padding*2)+(circle_out_diameter*3)+(circle_out_diameter*0.7*2)+(circle_out_diameter/5/3*2)
            float circle_in_diameter = circle_out_diameter / 5f;//内圆直径
            float circle_interval = circle_out_diameter * 0.7f;//圆形间距
            float circle_border = circle_out_diameter / (5f * 3f);//外圆边厚度
            for (int x = 0; x < 3; x++)
            {
                for (int y = 0; y < 3; y++)
                {
                    int index = x * 3 + y;
                    RectangleF out_rectf = new RectangleF(draw_padding + circle_border + y * circle_out_diameter + circle_interval * y, draw_padding + circle_border + x * circle_out_diameter + circle_interval * x, circle_out_diameter, circle_out_diameter);
                    RectangleF in_rectf = new RectangleF(out_rectf.Left + circle_in_diameter * 2f, out_rectf.Top + circle_in_diameter * 2f, circle_in_diameter, circle_in_diameter);
                    this.patternLockItems[index].OutRect = out_rectf;
                    this.patternLockItems[index].InRect = in_rectf;
                    this.patternLockItems[index].CenterPoint = new PointF(out_rectf.Left + out_rectf.Width / 2f, out_rectf.Top + out_rectf.Height / 2f);
                    this.patternLockItems[index].GP.Reset();
                    this.patternLockItems[index].GP.AddEllipse(out_rectf);
                }
            }
        }

        /// <summary>
        /// 重置控件状态
        /// </summary>
        public void Reset()
        {
            this.operateStatus = PatternLockOperateStatus.Normal;
            this.selectedPatternLockItems.Clear();
            this.mousedownobject = false;
            this.mousedownpoint = Point.Empty;

            this.Invalidate();
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 操作完成触发
        /// </summary>
        private void CompleteTrigger()
        {
            if (this.operateStatus == PatternLockOperateStatus.Sliding && this.selectedPatternLockItems.Count > 0)
            {
                this.operateStatus = PatternLockOperateStatus.Complete;
                this.Invalidate();

                PatternLockCompleteEventArgs arg = new PatternLockCompleteEventArgs(String.Concat(this.selectedPatternLockItems.Values.ToList<string>()), false);
                this.OnComplete(arg);

                if (arg.Result)
                {
                    this.operateStatus = PatternLockOperateStatus.Normal;
                    this.selectedPatternLockItems.Clear();
                }
                else
                {
                    this.operateStatus = PatternLockOperateStatus.Error;
                }
                this.Invalidate();
            }
        }

        #endregion

        #region 类

        /// <summary>
        /// 解锁图案选项
        /// </summary>
        internal class PatternLockItem
        {
            /// <summary>
            /// 图案外rect
            /// </summary>
            public RectangleF OutRect { get; set; }
            /// <summary>
            /// 图案内rect
            /// </summary>
            public RectangleF InRect { get; set; }
            /// <summary>
            /// 图案path
            /// </summary>
            public GraphicsPath GP { get; set; }
            /// <summary>
            /// 图案中心point
            /// </summary>
            public PointF CenterPoint { get; set; }
            /// <summary>
            /// 值
            /// </summary>
            public string Value { get; set; }
        }

        /// <summary>
        /// PatternLock操作状态
        /// </summary>
        internal enum PatternLockOperateStatus
        {
            /// <summary>
            /// 正常(无任何操作)
            /// </summary>
            Normal,
            /// <summary>
            /// 手势滑动中
            /// </summary>
            Sliding,
            /// <summary>
            /// 手势刚完成
            /// </summary>
            Complete,
            /// <summary>
            /// 错误(无任何操作)
            /// </summary>
            Error
        }

        #endregion

        #region 外观

        public class StyleAppearanceObject : AppearanceObjectBase
        {
            internal StyleAppearanceObject(ISkinObject owner, AppearanceObjectBase parent) : base(owner, parent) { }

            #region 属性

            private Color skinBackColor = Color.Empty;
            private readonly Color defaultBackColor = SystemColors.Control;
            private Color backColor = Color.Empty;
            /// <summary>
            /// 背景颜色
            /// </summary>
            [Description("背景颜色")]
            [PropertyOrder(-195)]
            [SkinProperty(true, true)]
            public Color BackColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinBackColor != Color.Empty)
                    {
                        return this.skinBackColor;
                    }

                    if (this.backColor != Color.Empty)
                    {
                        return this.backColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.BackColor;
                    }

                    return this.defaultBackColor;
                }
                set
                {
                    if (this.backColor == value)
                        return;

                    this.backColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeBackColor()
            {
                return this.backColor != Color.Empty;
            }
            private void ResetBackColor()
            {
                this.backColor = Color.Empty;
                this.Invalidate();
            }

            private Color skinTextColor = Color.Empty;
            private readonly Color defaultTextColor = SystemColors.ControlText;
            private Color textColor = Color.Empty;
            /// <summary>
            /// 文本颜色
            /// </summary>
            [Description("文本颜色")]
            [PropertyOrder(-194)]
            [SkinProperty(true, true)]
            public Color TextColor
            {
                get
                {
                    if (this.owner.GetSkinObjectSkinStateCore() && this.skinTextColor != Color.Empty)
                    {
                        return this.skinTextColor;
                    }

                    if (this.textColor != Color.Empty)
                    {
                        return this.textColor;
                    }

                    if (((Control)this.owner).Parent != null)
                    {
                        return ((Control)this.owner).Parent.ForeColor;
                    }

                    return this.defaultTextColor;
                }
                set
                {
                    if (this.textColor == value)
                        return;

                    this.textColor = value;
                    this.Invalidate();
                }
            }
            private bool ShouldSerializeTextColor()
            {
                return this.textColor != Color.Empty;
            }
            private void ResetTextColor()
            {
                this.textColor = Color.Empty;
                this.Invalidate();
            }

            private ItemAppearanceObject normal;
            /// <summary>
            /// 正常状态
            /// </summary>
            [Description("正常状态")]
            [PropertyOrder(-193)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            [SkinProperty(true, false)]
            public ItemAppearanceObject Normal
            {
                get
                {
                    if (this.normal == null)
                        this.normal = new ItemAppearanceObject(this.owner, this, SystemColors.GradientActiveCaption);
                    return this.normal;
                }
            }

            private ItemAppearanceObject executing;
            /// <summary>
            /// 处理中状态
            /// </summary>
            [Description("处理中状态")]
            [PropertyOrder(-192)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            [SkinProperty(true, false)]
            public ItemAppearanceObject Executing
            {
                get
                {
                    if (this.executing == null)
                        this.executing = new ItemAppearanceObject(this.owner, this, Color.DeepSkyBlue);
                    return this.executing;
                }
            }

            private ItemAppearanceObject error;
            /// <summary>
            /// 错误状态
            /// </summary>
            [Description("错误状态")]
            [PropertyOrder(-191)]
            [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
            [SkinProperty(true, false)]
            public ItemAppearanceObject Error
            {
                get
                {
                    if (this.error == null)
                        this.error = new ItemAppearanceObject(this.owner, this, Color.Tomato);
                    return this.error;
                }
            }

            #endregion

            public class ItemAppearanceObject : AppearanceObjectBase
            {
                internal ItemAppearanceObject(ISkinObject owner, AppearanceObjectBase parent, Color thumbColor) : base(owner, parent)
                {
                    this.defaultThumbColor = thumbColor;
                }

                #region 属性

                private Color skinThumbColor = Color.Empty;
                private Color defaultThumbColor = Color.Empty;
                private Color thumbColor = Color.Empty;
                /// <summary>
                /// 拇指颜色
                /// </summary>
                [Description("拇指颜色")]
                [PropertyOrder(-199)]
                [SkinProperty(true, false)]
                public Color ThumbColor
                {
                    get
                    {
                        if (this.owner.GetSkinObjectSkinStateCore())
                        {
                            return this.skinThumbColor;
                        }

                        if (this.thumbColor != Color.Empty)
                        {
                            return this.thumbColor;
                        }

                        return this.defaultThumbColor;
                    }
                    set
                    {
                        if (this.thumbColor == value)
                            return;

                        this.thumbColor = value;
                        this.Invalidate();
                    }
                }
                private bool ShouldSerializeThumbColor()
                {
                    return this.thumbColor != Color.Empty;
                }
                private void ResetThumbColor()
                {
                    this.thumbColor = Color.Empty;
                }

                #endregion

            }
        }

        #endregion

    }

}
